home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
makemdi2.zip
/
FRAME.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-25
|
31KB
|
1,110 lines
#define _FRAME_C
//-----------------------------------------------------------------
// APP.C - <description>
//
// MAKEMDI adaptation of Windows 3.1 SDK MAKEAPP system.
//
// MDI application design based on Chapter 7 of
// "Windows 3: A Developer's Guide" by Jeffrey Richter.
//
// Adaptation developed with permission of the author by
// John F. Holliday, Technisoft Corporation
// Telephone: (515) 472-9803, CompuServe: 71271,634
//
// [DMM] 25-Nov-1992: Fixed crashing on exit
// Also tabified file to tabsize of 4
//
// David M. Miller, Business Visions, Inc.
// Telephone: (212) 747-6118
// CompuServe: 72676,327
// internet: dmiller@hera.sbi.com
//-----------------------------------------------------------------
#include "makemdi.h"
BOOL Frame_Initialize(APP * papp)
{
WNDCLASS cls;
cls.hCursor = LoadCursor(NULL, IDC_ARROW);
cls.hIcon = LoadIcon(papp->hinst, MAKEINTRESOURCE(IDR_FRAMEICON));
cls.lpszMenuName = MAKEINTRESOURCE(IDR_FRAMEMENU);
cls.hInstance = papp->hinst;
cls.lpszClassName = CLASS_FRAME;
cls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
cls.lpfnWndProc = Frame_WndProc;
cls.style = CS_HREDRAW | CS_VREDRAW;
cls.cbWndExtra = sizeof(FRAME *);
cls.cbClsExtra = 0;
if (!RegisterClass(&cls))
return FALSE;
return TRUE;
}
void Frame_Terminate(APP * papp)
{
}
LRESULT CALLBACK _export Frame_WndProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
LRESULT lResult = 0;
FRAME *pfrm = Frame_GetPtr(hWnd);
if (pfrm == NULL) {
if (msg == WM_NCCREATE) {
pfrm = (FRAME *) LocalAlloc(LPTR, sizeof(FRAME));
if (pfrm == NULL)
return (LRESULT) FALSE;
pfrm->hWnd = hWnd;
Frame_SetPtr(hWnd, pfrm);
}
else
return DefWindowProc(hWnd, msg, wParam, lParam);
}
if (msg == WM_NCDESTROY) {
// [DMM] Added: save hwndClient before freeing pfrm
HWND hWndClient = pfrm->hWndClient;
if (pfrm->fpProcRibbon != NULL)
FreeProcInstance((FARPROC) pfrm->fpProcRibbon);
if (pfrm->hMenu != NULL)
DestroyMenu(pfrm->hMenu);
LocalFree((HLOCAL)OFFSETOF(pfrm));
pfrm = NULL;
Frame_SetPtr(hWnd, NULL);
// [DMM] Added: execution ends here on NCDESTROY
return DefFrameProc(hWnd, hWndClient, msg, wParam, lParam);
}
// Get the window handle of the active MDI child.
// This is NULL if no MDI children exist.
// Determine if the MDI child is maximized.
if (IsWindow(pfrm->hWndClient))
lResult = SendMessage(pfrm->hWndClient, WM_MDIGETACTIVE, 0, 0);
pfrm->hWndActiveMDIChild = (HWND) LOWORD(lResult);
pfrm->fMDIChildIsMaximized = HIWORD(lResult);
switch (msg) {
// Windows messages
HANDLE_MSG(pfrm, WM_CREATE, Frame_OnCreate);
HANDLE_MSG(pfrm, WM_DESTROY, Frame_OnDestroy);
HANDLE_MSG(pfrm, WM_CLOSE, Frame_OnClose);
HANDLE_MSG(pfrm, WM_QUERYENDSESSION, Frame_OnQueryEndSession);
HANDLE_MSG(pfrm, WM_ENDSESSION, Frame_OnEndSession);
HANDLE_MSG(pfrm, WM_PAINT, Frame_OnPaint);
HANDLE_MSG(pfrm, WM_ERASEBKGND, Frame_OnEraseBkgnd);
HANDLE_MSG(pfrm, WM_SIZE, Frame_OnSize);
HANDLE_MSG(pfrm, WM_ACTIVATE, Frame_OnActivate);
HANDLE_MSG(pfrm, WM_INITMENU, Frame_OnInitMenu);
HANDLE_MSG(pfrm, WM_INITMENUPOPUP, Frame_OnInitMenuPopup);
HANDLE_MSG(pfrm, WM_COMMAND, Frame_OnCommand);
HANDLE_MSG(pfrm, WM_SYSCOMMAND, Frame_OnSysCommand);
HANDLE_MSG(pfrm, WM_NCLBUTTONDBLCLK, Frame_OnNclButtonDown);
HANDLE_MSG(pfrm, WM_MENUSELECT, Frame_OnMenuSelect);
HANDLE_MSG(pfrm, WM_ENTERIDLE, Frame_OnEnterIdle);
// Frame window specific messages
HANDLE_MSG(pfrm, FW_MDICHILDDESTROY, Frame_OnMdiChildDestroy);
HANDLE_MSG(pfrm, FW_GETSTATBARRECT, Frame_OnGetStatBarRect);
HANDLE_MSG(pfrm, FW_DRAWSTATUSDIVIDE, Frame_OnDrawStatusDivide);
HANDLE_MSG(pfrm, FW_RESIZEMDICLIENT, Frame_OnResizeMdiClient);
HANDLE_MSG(pfrm, FW_SETMENUHELP, Frame_OnSetMenuHelp);
HANDLE_MSG(pfrm, FW_GETMENUHELP, Frame_OnGetMenuHelp);
// Application messages
HANDLE_MSG(pfrm, AW_PAINTMENUHELP, Frame_OnPaintMenuHelp);
default:
return DefFrameProc(hWnd, pfrm->hWndClient, msg, wParam, lParam);
}
}
HWND Frame_CreateWindow(LPCSTR lpszText,
int x,
int y,
int cx,
int cy,
HINSTANCE hinst)
{
return CreateWindowEx(0L,
CLASS_FRAME,
lpszText,
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
x, y, cx, cy,
NULL,
NULL,
hinst,
NULL);
}
//-Message handlers------------------------------------------------
BOOL Frame_OnCreate(FRAME * pfrm, CREATESTRUCT FAR * lpCreateStruct)
{
CLIENTCREATESTRUCT ccs;
pfrm->hMenu = LoadMenu(lpCreateStruct->hInstance,
MAKEINTRESOURCE(IDR_FRAMEMENU));
pfrm->fStatusBarOn = TRUE;
// Create the MDICLIENT window as a child of the frame.
ccs.hWindowMenu = GetSubMenu(GetMenu(pfrm->hWnd), 1);
ccs.idFirstChild = CMD_WINDOWCHILD;
pfrm->hWndClient = CreateWindow("MDIClient", "",
WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL |
WS_VISIBLE | WS_CLIPSIBLINGS, 0, 0, 0, 0,
pfrm->hWnd, NULL, lpCreateStruct->hInstance,
(LPSTR) (LPCLIENTCREATESTRUCT) & ccs);
// Create the Ribbon dialog box with Frame as owner.
pfrm->fpProcRibbon = (DLGPROC) MakeProcInstance((FARPROC) Ribbon_DlgProc, g_app.hinst);
pfrm->hdlgRibbon = CreateDialog(g_app.hinst,
MAKEINTRESOURCE(DLG_RIBBON), pfrm->hWnd,
pfrm->fpProcRibbon);
if (pfrm->hdlgRibbon == NULL) {
FreeProcInstance((FARPROC) pfrm->fpProcRibbon);
return (0);
}
return pfrm->hWndClient != NULL;
}
void Frame_OnDestroy(FRAME * pfrm)
{
PostQuitMessage(0);
}
void Frame_OnClose(FRAME * pfrm)
{
// Before closing the application, ask the MDI children if it
// is ok?
if ((BOOL) SendMessage(pfrm->hWnd, WM_QUERYENDSESSION, 0, 0)) {
SendMessage(pfrm->hWnd, WM_ENDSESSION, TRUE, 0);
DefFrameProc(pfrm->hWnd, pfrm->hWndClient, WM_CLOSE, 0, 0L);
}
}
BOOL Frame_OnQueryEndSession(FRAME * pfrm)
{
BOOL bResult = TRUE;
HWND hWndChild;
// Get the handle of the first MDI Child.
hWndChild = GetWindow(pfrm->hWndClient, GW_CHILD);
if (hWndChild != NULL) {
// Ask each child if it is OK to terminate.
do {
// Do not ask caption bars of iconic MDI Children.
if (GetWindow(hWndChild, GW_OWNER) != NULL)
continue;
bResult = FORWARD_WM_QUERYENDSESSION(hWndChild, SendMessage);
// If the MDI Child says that it is NOT OK, don't ask the
// rest of the MDI Children.
if (bResult == FALSE)
break;
}
while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
// If any MDI Child said NO, tell the other children that
// the session is NOT being terminated.
if (bResult == FALSE) {
HWND hWndTemp = hWndChild;
hWndChild = GetWindow(pfrm->hWndClient, GW_CHILD);
do {
// If this child is the one that said NO, stop.
if (hWndTemp == hWndChild)
break;
// Do not send to caption bars of iconic MDI Children.
if (GetWindow(hWndChild, GW_OWNER) != NULL)
continue;
// Tell child we are not ending the session (wParam is FALSE).
SendMessage(hWndChild, WM_ENDSESSION, FALSE, 0);
}
while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
}
}
return bResult;
}
void Frame_OnEndSession(FRAME * pfrm, BOOL fEnding)
{
HWND hWndChild;
// Get handle of first MDI Child window.
hWndChild = GetWindow(pfrm->hWndClient, GW_CHILD);
// If no MDI Children exist, we are done.
if (hWndChild != NULL) {
// Tell each MDI Child whether or not the session is ending.
do {
// Do not send to caption bars of iconic MDI Children.
if (GetWindow(hWndChild, GW_OWNER) != NULL)
continue;
FORWARD_WM_ENDSESSION(hWndChild, fEnding, SendMessage);
}
while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
}
}
void Frame_OnPaint(FRAME * pfrm)
{
PAINTSTRUCT ps;
// Since the only visible portion of the Frame's client area is
// the status bar when it is ON, this must mean that the status
// bar needs to be repainted.
// Set up the device context.
BeginPaint(pfrm->hWnd, &ps);
SendMessage(pfrm->hWnd, FW_GETSTATBARRECT, 0, (LPARAM)((LPRECT)&ps.rcPaint));
SetBkMode(ps.hdc, TRANSPARENT);
// If an MDI Child exists, the status bar must be updated by it.
if (pfrm->hWndActiveMDIChild) {
SendMessage( pfrm->hWndActiveMDIChild,
AC_PAINTSTATBAR,
(WPARAM) ps.hdc,
(LPARAM)((LPPAINTSTRUCT)&ps));
}
else {
// No MDI Child exists, the Frame can do whatever it wants here.
ps.rcPaint.top += (int) SendMessage(pfrm->hWnd, FW_DRAWSTATUSDIVIDE, 0,
(LPARAM)((LPPAINTSTRUCT)&ps));
LoadString(g_app.hinst, IDS_FRAMESTATUSBAR, g_app.szBuf, sizeof(g_app.szBuf));
TextOut(ps.hdc, 0, ps.rcPaint.top, g_app.szBuf, lstrlen(g_app.szBuf));
}
EndPaint(pfrm->hWnd, &ps);
}
BOOL Frame_OnEraseBkgnd(FRAME * pfrm, HDC hdc)
{
return FORWARD_WM_ERASEBKGND(pfrm->hWnd, hdc, DefWindowProc);
}
void Frame_OnSize(FRAME * pfrm, UINT state, int cx, int cy)
//-----------------------------------------------------------------
// Force MDICHILD window to be resized.
//-----------------------------------------------------------------
{
SendMessage(pfrm->hWnd, FW_RESIZEMDICLIENT, 0, 0);
}
void Frame_OnActivate(FRAME * pfrm, UINT state, HWND hWndActDeact, BOOL fMinimized)
{
switch (state) {
case WA_INACTIVE:
break;
case WA_ACTIVE:
SetFocus(pfrm->hWndClient);
break;
case WA_CLICKACTIVE:
break;
}
}
void Frame_OnInitMenu(FRAME * pfrm, HMENU hMenu)
//-----------------------------------------------------------------
// The user has entered the menu system, set any options.
//-----------------------------------------------------------------
{
CheckMenuItem(hMenu, CMD_OPTIONSSTATUS, MF_BYCOMMAND |
(pfrm->fStatusBarOn ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(hMenu, CMD_OPTIONSRIBBON, MF_BYCOMMAND |
(IsWindowVisible(pfrm->hdlgRibbon) ? MF_CHECKED : MF_UNCHECKED));
}
void Frame_OnInitMenuPopup(FRAME * pfrm, HMENU hMenu, int item, BOOL fSystemMenu)
{
}
void Frame_OnCommand(FRAME * pfrm, int id, HWND hWndCtl, UINT code)
{
BOOL fCallDefProc = FALSE;
WORD wTemp;
// If a child is being activated via the "Window" menu, let
// the DefFrameProc handle it.
if (id >= CMD_WINDOWCHILD)
fCallDefProc = TRUE;
else
switch (id) {
case CMD_FILEOPENSHEET:
// Get the # of sheets already created and increment by 1.
wTemp = pfrm->wNumSheets + 1;
pfrm->wNumSheets = wTemp;
// The sheet's caption should display the sheet number.
wsprintf(g_app.szBuf, "Sheet%d", wTemp);
// Create the MDI Child window.
Frame_CreateMDIChild(CLASS_SHEET, g_app.szBuf, 0,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
pfrm->hWndClient, g_app.hinst, 0);
// Make sure the ribbon is enabled when any children exist.
EnableWindow(pfrm->hdlgRibbon, TRUE);
break;
case CMD_FILEOPENCHART:
// Get the # of charts already created and increment by 1.
wTemp = pfrm->wNumCharts + 1;
pfrm->wNumCharts = wTemp;
// The chart's caption should display the chart number.
wsprintf(g_app.szBuf, "Chart%d", wTemp);
// Create the MDI Child window.
Frame_CreateMDIChild(CLASS_CHART, g_app.szBuf, 0,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
pfrm->hWndClient, g_app.hinst, 0);
// Make sure the ribbon is enabled when any children exist.
EnableWindow(pfrm->hdlgRibbon, TRUE);
break;
case CMD_OPTIONSSTATUS:
// Toggle the status of the status bar, resize the MDICLIENT.
pfrm->fStatusBarOn = !pfrm->fStatusBarOn;
SendMessage(pfrm->hWnd, FW_RESIZEMDICLIENT, 0, 0);
break;
case CMD_OPTIONSRIBBON:
// Toggle the status of the ribbon, resize the MDICLIENT.
ShowWindow(pfrm->hdlgRibbon,
IsWindowVisible(pfrm->hdlgRibbon) ? SW_HIDE : SW_SHOW);
SendMessage(pfrm->hWnd, FW_RESIZEMDICLIENT, 0, 0);
break;
case CMD_EXIT:
SendMessage(pfrm->hWnd, WM_CLOSE, 0, 0L);
break;
case CMD_HELPINDEX:
case CMD_HELPKEYBOARD:
case CMD_HELPCOMMANDS:
case CMD_HELPPROCEDURES:
case CMD_HELPUSINGHELP:
MessageBox(pfrm->hWnd, "Option not implemented.", g_app.szName, MB_OK);
break;
// case CMD_ABOUT:
// {
// FARPROC fpProc;
// fpProc = MakeProcInstance(AboutProc, g_app.hinst);
// DialogBox(g_app.hinst, "About", pfrm->hWnd, fpProc);
// FreeProcInstance(fpProc);
// break;
// }
case CMD_WINDOWTILEVERT:
// Call our own function to perform vertical tiling.
Frame_TileVertically(pfrm->hWndClient);
break;
case CMD_WINDOWTILEHORIZ:
// Let the MDICLIENT window do the repositioning.
SendMessage(pfrm->hWndClient, WM_MDITILE, 0, 0);
break;
case CMD_WINDOWCASCADE:
// Let the MDICLIENT window do the repositioning.
SendMessage(pfrm->hWndClient, WM_MDICASCADE, 0, 0);
break;
case CMD_WINDOWARRANGEICONS:
// Let the MDICLIENT window do the repositioning.
SendMessage(pfrm->hWndClient, WM_MDIICONARRANGE, 0, 0);
break;
default:
// Menu options not processed by the Frame window must
// be passed to the MDI Children for processing.
FORWARD_WM_COMMAND(pfrm->hWndActiveMDIChild,
id, hWndCtl, code,
SendMessage);
break;
}
if (fCallDefProc)
DefFrameProc(pfrm->hWnd,
pfrm->hWndClient, WM_COMMAND,
(WPARAM) id, MAKELPARAM(hWndCtl, code));
}
void Frame_OnSysCommand(FRAME * pfrm, WORD cmd, int x, int y)
//-----------------------------------------------------------------
// Set focus to frame window. This causes any comboboxes
// in the ribbon to be closed.
//-----------------------------------------------------------------
{
SetFocus(pfrm->hWnd);
DefFrameProc(pfrm->hWnd,
pfrm->hWndClient, WM_SYSCOMMAND,
(WPARAM) cmd,
MAKELPARAM(x, y));
}
void Frame_OnNclButtonDown(FRAME * pfrm, BOOL fDoubleClick, int x, int y, UINT codeHitTest)
//-----------------------------------------------------------------
// Code to allow double-clicking the MDI Child's system menu
// to close the MDI Child window.
//-----------------------------------------------------------------
{
RECT rc;
BITMAP Bitmap;
HBITMAP hBitmap;
DWORD dwResult;
LPARAM lParam;
BOOL fCallDefProc = TRUE;
if (fDoubleClick && (codeHitTest == HTMENU)) {
// If the active child is not maximized, nothing to do.
dwResult = SendMessage(pfrm->hWndClient, WM_MDIGETACTIVE, 0, 0);
if (HIWORD(dwResult) == 1) {
// Get position and dimensions of the MDI Child's system menu in
// the Frame's menu bar.
// Get position and dimensions of the Frame window.
GetWindowRect(pfrm->hWnd, &rc);
// Get handle to the CLOSE BOX bitmaps.
hBitmap = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CLOSE));
// Get dimensions of the bitmaps.
GetObject(hBitmap, sizeof(BITMAP), (LPSTR) (LPBITMAP) & Bitmap);
DeleteBitmap(hBitmap);
// Adjust the rectangle.
rc.top += GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
rc.bottom = rc.top + Bitmap.bmHeight;
rc.left += GetSystemMetrics(SM_CXFRAME);
// The close bitmap includes the Application and MDI Child CLOSE
// boxes. So we only want half of the bitmap's width.
rc.right = rc.left + Bitmap.bmWidth / 2;
// If the mouse cursor is within this rectangle, tell the
// MDI Child window to close.
lParam = MAKELPARAM(x, y);
if (PtInRect(&rc, MAKEPOINT(lParam))) {
SendMessage((HWND) LOWORD(dwResult),
WM_SYSCOMMAND, SC_CLOSE, lParam);
fCallDefProc = FALSE;
}
}
}
if (fCallDefProc)
DefFrameProc(pfrm->hWnd,
pfrm->hWndClient,
(fDoubleClick) ? WM_NCLBUTTONDBLCLK : WM_NCLBUTTONDOWN,
(WPARAM) (UINT) codeHitTest,
MAKELPARAM(x, y));
}
void Frame_OnMenuSelect(FRAME * pfrm, HMENU hMenu, int item, HMENU hMenuPopup, UINT flags)
//-----------------------------------------------------------------
// The user has highlighted a menu item.
//-----------------------------------------------------------------
{
WORD wTemp;
if (flags == -1 && (hMenu == (HMENU) 0)) {
// User has stopped using the menu system.
SendMessage(pfrm->hWnd, FW_SETMENUHELP, 0, 0);
return;
}
// If wTemp == 0, at end of switch, MDI Child handled the message.
wTemp = 0;
switch (flags & (MF_POPUP | MF_SYSMENU)) {
case 0:
// item is a menu item ID NOT on the app's system menu.
if (pfrm->hWndActiveMDIChild != NULL) {
// An MDI Child exists.
if (pfrm->fMDIChildIsMaximized) {
// If menu item from the MDI Child's system menu, set
// the MF_SYSMENU bit in the lParam parameter.
HMENU hTemp = GetSubMenu(GetMenu(pfrm->hWnd), 0);
if ((int) GetMenuState(hTemp, item, MF_BYCOMMAND) != -1)
flags |= MF_SYSMENU;
}
// Make active MDI Child think that it received the
// WM_MENUSELECT message.
FORWARD_WM_MENUSELECT(
pfrm->hWndActiveMDIChild,
hMenu, item, hMenuPopup,
flags,
SendMessage);
wTemp = 0; // MDI Child handled the message.
break;
}
wTemp = IDS_FRAMEMENUID + item;
break;
case MF_POPUP:
if (pfrm->hWndActiveMDIChild != NULL) {
// An MDI Child exists.
if (pfrm->fMDIChildIsMaximized) {
// If popup menu is first top-level menu, it is the
// MDI Child's system menu, set the MF_SYSMENU flag.
if (hMenuPopup == GetSubMenu(GetMenu(pfrm->hWnd), 0))
flags |= MF_SYSMENU;
}
// Make active MDI Child think that it received the
// WM_MENUSELECT message.
FORWARD_WM_MENUSELECT(
pfrm->hWndActiveMDIChild,
hMenu, item, hMenuPopup,
flags,
SendMessage);
wTemp = 0; // MDI Child handled the message.
break;
}
// Calculate the index of the top-level menu.
hMenu = GetMenu(pfrm->hWnd);
wTemp = GetMenuItemCount(hMenu);
while (wTemp--)
if (GetSubMenu(hMenu, wTemp) == hMenuPopup)
break;
wTemp += IDS_FRAMEPOPUPID + 1; // Jump over system menu.
break;
case MF_SYSMENU:
// item is menu item ID from system menu.
wTemp = IDS_FRAMEMENUID + ((item & 0x0FFF) >> 4);
break;
case MF_POPUP | MF_SYSMENU:
// item is handle to app's sys menu.
wTemp = IDS_FRAMEPOPUPID;
break;
}
// If message handled by MDI Child, nothing more to do.
if (wTemp != 0) {
// Tell the Frame that the Frame window should display the
// help text and the identifier for the help text.
SendMessage(pfrm->hWnd, FW_SETMENUHELP,
(WPARAM) pfrm->hWnd, (LPARAM) wTemp);
}
}
void Frame_OnEnterIdle(FRAME * pfrm, WORD source, HWND hWndSource)
{
RECT rc;
PAINTSTRUCT ps;
if (source == MSGF_MENU) {
// User has stopped scrolling through menu items.
// If Menu help already displayed, nothing more to do.
// This is signaled by hWndMenu help being -1.
if (pfrm->hWndMenuHelp != (HWND) - 1) {
// Display new menu help, invalidate the status bar.
SendMessage(pfrm->hWnd, FW_GETSTATBARRECT, 0, (LPARAM)((LPRECT)&rc));
InvalidateRect(pfrm->hWnd, &rc, TRUE);
// BeginPaint is OK because an invalid rectangle must exist because
// of the call to InvalidateRect above. This causes the background
// for the Frame's client area to be drawn correctly.
BeginPaint(pfrm->hWnd, &ps);
// Set up the device context.
SetBkMode(ps.hdc, TRANSPARENT);
// Send message to window that last received a WM_MENUSELECT
// message to tell it to paint the status bar with the
// appropriate menu help text.
SendMessage(pfrm->hWndMenuHelp, AW_PAINTMENUHELP, 0,
(LPARAM)((LPPAINTSTRUCT)&ps));
EndPaint(pfrm->hWnd, &ps);
// Set flag notifying this message that the most recently selected
// menu item has had its help text painted. This stops unsightly
// screen flicker.
pfrm->hWndMenuHelp = (HWND) - 1;
}
}
}
void Frame_OnMdiChildDestroy(FRAME * pfrm)
//-----------------------------------------------------------------
// Message is posted by an MDI Child just before it is destroyed.
//-----------------------------------------------------------------
{
// If another MDI Child exists, nothing to do.
if (pfrm->hWndActiveMDIChild != NULL)
return;
// Set the menu bar and accelerator table to the Frame's defaults.
Frame_ChangeMDIMenu( pfrm->hWnd,
pfrm->hWndClient,
pfrm->hMenu,
CMD_WINDOWTILEVERT);
g_app.hAccelTable = NULL;
// Force the status bar to be updated.
InvalidateRect(pfrm->hWnd, NULL, TRUE);
// Disable the Ribbon.
EnableWindow(pfrm->hdlgRibbon, FALSE);
}
void Frame_OnGetStatBarRect(FRAME * pfrm, LPRECT lpRect)
{
// Get the client area of the Frame window.
GetClientRect(pfrm->hWnd, lpRect);
// If the status bar is OFF, set the status bar to have no height.
if (pfrm->fStatusBarOn) {
// Change the dimensions so that the status bar is the height of
// one line of text plus a small border.
HDC hdc;
TEXTMETRIC tm;
hdc = GetDC(pfrm->hWnd);
GetTextMetrics(hdc, &tm);
ReleaseDC(pfrm->hWnd, hdc);
lpRect->top = lpRect->bottom - tm.tmHeight -
GetSystemMetrics(SM_CYBORDER);
}
else
lpRect->top = lpRect->bottom;
}
void Frame_OnDrawStatusDivide(FRAME * pfrm, LPPAINTSTRUCT ps)
{
HPEN hPen;
DWORD dwResult = GetSystemMetrics(SM_CYBORDER);
// Draw a line separating the status bar from the MDICLIENT window.
hPen = CreatePen(PS_SOLID, (int) dwResult, RGB(0, 0, 0));
hPen = SelectPen(ps->hdc, hPen);
MoveTo(ps->hdc, 0, ps->rcPaint.top);
LineTo(ps->hdc, ps->rcPaint.right, ps->rcPaint.top);
DeletePen(SelectPen(ps->hdc, hPen));
}
void Frame_OnResizeMdiClient(FRAME * pfrm)
{
RECT rc, rcTemp;
// Sent when the Frame window is resized or when the status bar
// and ribbon are toggled.
GetClientRect(pfrm->hWnd, &rc);
if (IsWindow(pfrm->hdlgRibbon) && IsWindowVisible(pfrm->hdlgRibbon)) {
// Ribbon is displayed, adjust rectangle.
GetClientRect(pfrm->hdlgRibbon, &rcTemp);
rc.top += rcTemp.bottom;
rc.bottom -= rcTemp.bottom;
}
// Get the dimensions of the status bar rectangle and adjust the
// dimensions of the MDICLIENT window.
SendMessage(pfrm->hWnd, FW_GETSTATBARRECT, 0, (LPARAM)((LPRECT)&rcTemp));
rc.bottom -= rcTemp.bottom - rcTemp.top;
MoveWindow(pfrm->hWndClient, 0, rc.top, rc.right, rc.bottom, TRUE);
}
void Frame_OnSetMenuHelp(FRAME * pfrm, HWND hWndMenuHelp, DWORD dwMenuHelp)
//-----------------------------------------------------------------
// Called by the Frame and MDI Children whenever a
// WM_MENUSELECT message is received.
//-----------------------------------------------------------------
{
// Save the handle of the window sending the message.
pfrm->hWndMenuHelp = hWndMenuHelp;
// Save the menu help code that the window sent too.
pfrm->dwMenuHelp = dwMenuHelp;
// When the Frame or MDI Child receive a WM_MENUSELECT message
// specifying that the menu system is closed
// (dwMenuHelp == MAKELONG(-1, 0)), the menu help should disappear and
// be replaced by the proper information on the status bar.
if (hWndMenuHelp == NULL) {
RECT rc;
SendMessage(pfrm->hWnd, FW_GETSTATBARRECT, 0, (LPARAM)((LPRECT)&rc));
// Force status bar to be updated.
InvalidateRect(pfrm->hWnd, &rc, TRUE);
}
}
DWORD Frame_OnGetMenuHelp(FRAME * pfrm)
//-----------------------------------------------------------------
// Sent by the Frame or MDI Child when they
// receive a AW_PAINTMENUHELP message.
//-----------------------------------------------------------------
{
return pfrm->dwMenuHelp;
}
void Frame_OnPaintMenuHelp(FRAME * pfrm, LPPAINTSTRUCT psStatus)
//-----------------------------------------------------------------
// Message sent from Frame window to notify Frame that it should
// paint the status bar text for the last highlighted menu item.
//-----------------------------------------------------------------
{
LRESULT lResult;
// Ask the Frame window what the last selected menu ID was.
// This value was sent to the frame by this window during the
// processing for the WM_MENUSELECT message.
lResult = SendMessage(pfrm->hWnd, FW_GETMENUHELP, 0, 0);
// Draw the horizontal dividing line separating the Status bar
// from the MDICLIENT window.
psStatus->rcPaint.top += (int)
SendMessage(pfrm->hWnd, FW_DRAWSTATUSDIVIDE, 0, (LPARAM) psStatus);
// Construct the string that is to be displayed.
LoadString(g_app.hinst, LOWORD(lResult), g_app.szBuf, sizeof(g_app.szBuf));
// Paint the menu help text in the status bar.
TextOut(psStatus->hdc, 0, psStatus->rcPaint.top, g_app.szBuf, lstrlen(g_app.szBuf));
}
//-Utility routines------------------------------------------------
HWND WINAPI Frame_CreateMDIChild(LPSTR szClassName,
LPSTR szWindowName,
DWORD dwStyle,
short x,
short y,
short nWidth,
short nHeight,
HWND hWndMDIClient,
HANDLE hInstance,
LONG lParam)
{
MDICREATESTRUCT cs;
HWND hWndChild;
cs.szClass = szClassName;
cs.szTitle = szWindowName;
cs.hOwner = hInstance;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.style = dwStyle;
cs.lParam = lParam;
hWndChild = (HWND) SendMessage(hWndMDIClient, WM_MDICREATE,
0, (LPARAM)((LPMDICREATESTRUCT)&cs));
return (hWndChild);
}
// Function to change the menu in the Frame window whenever a
// new MDI Child becomes active.
void WINAPI Frame_ChangeMDIMenu(HWND hWndFrame,
HWND hWndClient,
HMENU hMenuNew,
WORD wMenuID)
{
WORD wCount;
HMENU hSubMenu = 0;
// Get number of top-level menu items in the menu used by the window
// being activated.
wCount = GetMenuItemCount(hMenuNew);
// Locate the POPUP menu that contains the menu option with the
// 'wMenuID' identifier in it. This must be an identifier for an option
// in the new menu's "Window" popup menu.
while (wCount) {
hSubMenu = GetSubMenu(hMenuNew, wCount - 1);
if ((int) GetMenuState(hSubMenu, wMenuID, MF_BYCOMMAND) != -1)
break;
wCount--;
}
// Tell the MDICLIENT window to setup the new menu.
SendMessage(hWndClient, WM_MDISETMENU, 0, MAKELONG(hMenuNew, hSubMenu));
DrawMenuBar(hWndFrame);
}
void WINAPI Frame_TileVertically(HWND hWndMDIClient)
{
int nNumWndsOnRow, nOpenMDIChildren = 0, nTopOfBottomIconRow = 0;
int nCrntCol, nColWidth, nCrntRow, nNumRows, nRowHeight, nMinWndHeight;
HWND hWndChild;
HANDLE hWinPosInfo;
RECT rc;
POINT Point;
DWORD dwChildInfo;
// Assume that scrollbars will be off after windows are tiled.
// By forcing them off now, GetClientRect will return the correct size.
ShowScrollBar(hWndMDIClient, SB_BOTH, 0);
// The WM_MDICASCADE and WM_MDITILE messages cause the icons to be
// arranged. So we will too. In fact, this is necessary to locate
// the top of the bottom icon row in the next step of this function.
SendMessage(hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
// Get handle to first MDI Child window.
hWndChild = GetWindow(hWndMDIClient, GW_CHILD);
do {
if (IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL) {
// Window is iconic and window is NOT an icon's caption.
// Get client area of the icon window.
GetWindowRect(hWndChild, &rc);
// rc.top is in screen coordinates.
nTopOfBottomIconRow = max(nTopOfBottomIconRow, rc.top);
}
if (!IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL)
++nOpenMDIChildren;
}
while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
// All MDI Children are icons, no tiling is necessary.
if (nOpenMDIChildren == 0)
return;
// Find height of usable client area for tiling.
GetClientRect(hWndMDIClient, &rc);
if (nTopOfBottomIconRow) {
// At least one MDI Child is iconic.
// Convert coordinates from screen to client.
Point.x = 0;
Point.y = nTopOfBottomIconRow;
ScreenToClient(hWndMDIClient, &Point);
// Point.y is top of bottom icon row in client coordinates.
rc.bottom = Point.y;
}
// Restore the active MDI child if it's maximized
dwChildInfo = SendMessage(hWndMDIClient, WM_MDIGETACTIVE, 0, 0);
if (HIWORD(dwChildInfo) == 1)
ShowWindow((HWND) LOWORD(dwChildInfo), SW_RESTORE);
// Calculate the minimum desired height of each MDI Child.
nMinWndHeight = max(1, rc.bottom / (5 * GetSystemMetrics(SM_CYCAPTION)));
// Calculate the number of rows that will be tiled.
nNumRows = min(nOpenMDIChildren, nMinWndHeight);
// Calculate the height of each row.
nRowHeight = rc.bottom / nNumRows;
// Get the handle to the first MDI Child window.
hWndChild = GetWindow(hWndMDIClient, GW_CHILD);
// Prime the storage of positioning information.
hWinPosInfo = BeginDeferWindowPos(nOpenMDIChildren);
// Execute the loop for each row.
for (nCrntRow = 0; nCrntRow < nNumRows; nCrntRow++) {
// Calculate the number of MDI Children that will appear on this row.
nNumWndsOnRow = nOpenMDIChildren / nNumRows +
((nOpenMDIChildren % nNumRows > (nNumRows - (nCrntRow + 1))) ? 1 : 0);
// Calculate the width of each of these children.
nColWidth = rc.right / nNumWndsOnRow;
// Fill each column with an MDI Child window.
for (nCrntCol = 0; nCrntCol < nNumWndsOnRow;) {
if (!IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL) {
// Child is NOT iconic and not an icon's caption bar.
// Tell windows what the new position and dimensions of this
// MDI Child should be.
hWinPosInfo = DeferWindowPos(hWinPosInfo, hWndChild, NULL,
nCrntCol * nColWidth, nCrntRow * nRowHeight, nColWidth,
nRowHeight, SWP_NOACTIVATE | SWP_NOZORDER);
// Go to the next column.
nCrntCol++;
}
// Get handle to the next MDI Child window.
hWndChild = GetWindow(hWndChild, GW_HWNDNEXT);
}
}
// All of the positioning has been set. Now, tell Windows to update
// all of the windows at once.
EndDeferWindowPos(hWinPosInfo);
}